/** @file */
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include "defines.h"
#include "login.h"

const std::string file_name = "./uzytkownicy.flimbaza";
const char PRINT_SEPARATOR = ':';


/* cant touch this */
#define MODE_OFF -1
#define MODE_USER 0
#define MODE_ADMIN 1

static struct {
	
	/* mode
	 *jeśli równe -1 = nie uwierzytelniono
	 *jeśli równe 0 = uwierzytelniono użytkownika
	 *jeśli równe 1 = uwierzytelniono admina
	 */
	signed char mode;
	
	/* nazwa zalogowanego użytkownika */
	std::string user;
	/* hasło zalogowanego użytkownika */
	std::string pass;

	
} log = { MODE_OFF, "", ""};

/* na sztywno wpisani admini */
const static struct {
	std::string user;
	std::string pass;
} hardwire_admins[] = {
	{ "kamil", "kamil" },
};
	
/**
 * @brief uwierzytelnij uwierzytelnij hasło i użytkownika
 * @param user wpisana nazwa użytkownika
 * @param password hasło użytkownika
 * @return mniejsze od zera jeśli błedne hasło lub nazwa użytkownika, 0 jesli użytkownik uwierzytelniony, 1 jeśli administrator uwierzytelniony
 */
int uwierzytelnij(std::string user, std::string pass)
{
	std::ifstream ffile;
	std::string _user, _pass;
	int _mode;
	bool found = false;
	int i;
	const int len = sizeof(hardwire_admins)/sizeof(*hardwire_admins); /* array(hardwire_admins) */
	
	/* jeśli użytkownika o nazwie user jest wpisany na sztywno i jest wpisany do pliku,
	 *  to hasło musi pasować do tego co jest w pliku 
	 */
	
	/* przeszukaj wpisanych na sztwno adminów w poszukiwaniu autoryzacji */
	_mode = MODE_ADMIN;
	for( i = 0; i < len; i++) {
		_user = hardwire_admins[i].user;
		_pass = hardwire_admins[i].pass;
		if ( !_user.compare(user) ) {
			found = true;
			break; /* znaleziono użytkownika o podanej nazwie */
		}
	}
	
	/* przeszukaj plik w poszukiwaniu uzytkowników */
	ffile.open(file_name.c_str());
	if ( ffile.good() ) {
		std::string line;
		
		while ( std::getline(ffile, line) ) {
			std::istringstream stream(line);
			std::string b_user, b_pass, b_mode; /* buffers */
			std::string buff;
			
			std::getline(stream, b_user, PRINT_SEPARATOR);
			std::getline(stream, b_pass, PRINT_SEPARATOR);
			std::getline(stream, b_mode, PRINT_SEPARATOR);
			
			/* rest ignored */
			std::getline(stream, buff, '\n');
			
			if ( !b_user.compare(user) ) {
				found = true;
				_user = b_user;
				_pass = b_pass;
				_mode = atoi(b_mode.c_str());
				break; /* znaleziono użytkownika o podanej nazwie */
			}
		}
		ffile.close();
	}
	
	if ( !found )
		goto ERR_NO_SUCH_USER;
	
	/* tutaj jest tak:
	 * znaleziono użytkownika imieniem _user,
	 * o haśle _pass, i modzie _mode;
	 * */
	
	/* jesteśmy adminem ? */
	if ( log.mode == MODE_ADMIN ) {
		/* admin może podać złe hasło, i tak go przelogujemy */
		log.user = _user;
		log.pass = _pass;
		log.mode = _mode;
	} else {
		/* sprawdz hasło */
		if ( !_pass.compare(pass) ) {
			/* logowanie udało się */
			log.user = _user;
			log.pass = _pass;
			log.mode = _mode;
		}
	}
	
	return log.mode;
	
ERR_NO_SUCH_USER:
	/* nie ma takiego użytkownika */
	return -3;
}

/**
 * @brief admin sprawdz jako kto jesteś zalogowany
 * @return zwraca 1 jeśli zalogowany jest admin, w przeciwnym wypadku 0
 */
int admin()
{
	/* co jeśli log.mode == MODE_OFF, prosze cie.. */
	return log.mode == MODE_ADMIN ? 1 : 0;
}

/**
 * @brief logged sprawdza czy jesteś zalogowany
 * @return zwraca 1 jeśli udało się zalogować, w przeciwnym wypdadku 0
 */
int logged()
{
	return log.mode == MODE_OFF ? 0 : 1;
}

/**
 * @brief get_user
 * @return zwraca nazwe zalogowanego użytkownika
 */
const std::string get_user()
{
	return log.user;
}

/**
 * @brief login_useradd dodaje użytkownika
 * @param user nazwa użytkownika
 * @param pass hasło użytkownika
 * @param mode czy jest adminem
 * @return mniejsze od zera jeśli błąd, 0 jeśli sukces
 */
int login_useradd(std::string user, std::string pass, int mode)
{
	std::fstream ffile;
	std::string line;
	std::string newfile = "";
	std::string buff;
	
	if ( log.mode == MODE_OFF ) return -2;
	if ( log.mode == MODE_USER ) {
		/* user can change only hes password */
		if ( user.compare(log.user) )
			return -1;
		/* muhahahaha nie tak łatwo :p */
		mode = MODE_USER;
	}
			
	ffile.open(file_name.c_str());
	if ( !ffile.good() ) {
		/* truncate it (create it) */
		ffile.open(file_name.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::trunc);
		/* still err? */
		if ( !ffile.good() ) {
			/* cannot open and create file */
			return -2;
		}
	}
	
	while ( std::getline(ffile, line, '\n') ) {
		std::istringstream stream(line);
		std::string b_user; /* buffers */
		
		std::getline(stream, b_user, PRINT_SEPARATOR);
		std::getline(stream, buff, '\n');
		
		if ( !b_user.compare(user) ) {
			break; /* znaleziono użytkownika o podanej nazwie */
		}
		
		/* newfile zawiera linie z innymi użytkownikami */
		newfile = newfile + line + '\n';
	}
	
	/* add the user, pass and mode info to the newfile */
    newfile = newfile + user + PRINT_SEPARATOR + pass + PRINT_SEPARATOR + (char)(mode+(char)'0') + PRINT_SEPARATOR + '\n';

	/* wszystkie pozostałę linie do newfile */
	while ( std::getline(ffile, buff, '\n') ) {
		newfile = newfile + buff + '\n';
	}
	
	ffile.close();
	
	/* truncate the file */
	ffile.open(file_name.c_str(), std::ios::out | std::ios::trunc );
	if ( !ffile.good() ) {
		/* cannot open file */
		return -3;
	}
	/* send the dragons */
	ffile << newfile;
	ffile.close();
	
	return 0;
}

/**
 * @brief login_userdel usuwa uzytkwnika
 * @param user nazwa użytkownika
 * @return mniejsze od zera jeśli błąd, 0 jeśli sukces
 */
int login_userdel(std::string user)
{	
	std::fstream ffile;
	std::string line;
	std::string newfile = "";
	std::string buff;
	bool found = false;
	
	if ( log.mode != MODE_ADMIN )
		return -1;
			
	ffile.open(file_name.c_str());
	if ( !ffile.good() ) {
		/* cannot open file */
		return -2;
	}
	
	while ( std::getline(ffile, line, '\n') ) {
		std::istringstream stream(line);
		std::string b_user; /* buffers */
		
		std::getline(stream, b_user, PRINT_SEPARATOR);
		std::getline(stream, buff, '\n');
		
		if ( !b_user.compare(user) ) {
			found = true;
			break; /* znaleziono użytkownika o podanej nazwie */
		}
		
		/* newfile zawiera linie z innymi użytkownikami */
		newfile = newfile + line + '\n';
	}
	
	if ( !found ) {
		/* user not found */
		ffile.close();
		return -1;
	}
	
	/* wszystkie pozostałę linie do newfile */
	while ( std::getline(ffile, buff, '\n') ) {
		newfile = newfile + buff + '\n';
	}
	
	ffile.close();
	
	/* truncate the file */
	ffile.open(file_name.c_str(), std::ios::out | std::ios::trunc );
	if ( !ffile.good() ) {
		/* cannot open file */
		return -3;
	}
	/* send the dragons */
	ffile << newfile;
	ffile.close();
	
	return 0;
}


